﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.Runtime.Caching;
using System.Timers;

namespace blackhouse.WebNemo.Data.Cache
{
    public class NemoChangeMonitor : ChangeMonitor
    {

        #region Fields

        private NemoCache cache = new NemoCache(TimeSpan.FromMinutes(2), GetConnectionString());
        private ReadOnlyCollection<string> keys;
        private readonly Timer timer;
        private readonly DateTime lastTime;
        private bool isDisposing;
        private static readonly List<NemoChangeMonitor> Monitors = new List<NemoChangeMonitor>();
        private static volatile object _lockMonitors = new object();

        #endregion

        #region Properties

        public override string UniqueId {
            get { return this.cache.GetCurrentCacheKey(); }
        }

        #endregion

        #region Constructors

        public NemoChangeMonitor(IGroupIdsProvider idsProvider)
            : this(idsProvider.GetIds()) { }

        public NemoChangeMonitor(params int[] groupIds) {
            this.cache.Reset();
            this.cache.SetKey("monitor");
            this.cache.SetDependencyTables(groupIds);
            this.keys = new List<string>(groupIds.Select(s => s.ToString())).AsReadOnly();
            this.lastTime = this.cache.GetLastUpdateTime();
            this.timer = new Timer();
            this.timer.Interval = 1000;
            this.timer.Elapsed += CheckIsChanged;
            this.timer.Enabled = true;
            lock (_lockMonitors) {
                Monitors.Add(this);
            }
            this.InitializationComplete();
        }


        #endregion

        private static string GetConnectionString() {
            var connString = ConfigurationManager.AppSettings["MSSQLConnectionString"];
            if (string.IsNullOrEmpty(connString)) {
                var css = ConfigurationManager.ConnectionStrings["MSSQLConnectionString"];
                if (css == null && ConfigurationManager.ConnectionStrings.Count > 0)
                    css = ConfigurationManager.ConnectionStrings[0];
                if (css != null)
                    connString = css.ConnectionString;
            }
            return connString;
        }

        private void CheckIsChanged(object sender, ElapsedEventArgs e) {
            if (this.isDisposing) return;
            if (this.cache.GetLastUpdateTime() > this.lastTime)
                OnChanged(null);
        }

        internal static void RaiseCheckOnMonitors() {
            lock (_lockMonitors) {
                var stack = new Stack<NemoChangeMonitor>();
                foreach (var monitor in Monitors)
                    stack.Push(monitor);
                while (stack.Count > 0) {
                    var workMonitor = stack.Pop();
                    if (workMonitor.isDisposing) continue;
                    workMonitor.CheckIsChanged(null, null);
                }
            }
        }


        protected override void Dispose(bool disposing) {
            this.isDisposing = true;
            this.timer.Dispose();
            this.cache = null;
            lock (_lockMonitors) {
                Monitors.Remove(this);
            }
        }

    }
}
